package nginx_handler

import (
	"errors"
	"fmt"
	logger "gitee.com/zaper/private-logger"
	"gitee.com/zaper/route-service/model"
	crossplane "github.com/nginxinc/nginx-go-crossplane"
	"os"
	"sync"
)

var (
	smNginxConf sync.Mutex
)

func NginxConfHandler(path string, srvConf *model.ServerConf) error {
	smNginxConf.Lock()
	defer smNginxConf.Unlock()
	if path == "" || srvConf == nil {
		return errors.New("NginxConfHandler input param is nil")
	}
	payload, err := parseNginxConf(path)
	if err != nil {
		logger.Errorf("Parse nigix fail")
		return err
	}
	setPartBlock(srvConf, payload)
	if err = writeNginxConf(path, payload); err != nil {
		return err
	}
	return nil
}

func parseNginxConf(path string) (*crossplane.Payload, error) {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		logger.Errorf("nginx conf stat is fail %s", err)
		return nil, err
	}
	payload, err := crossplane.Parse(path, &crossplane.ParseOptions{
		StopParsingOnError: true,
	})
	if err != nil {
		logger.Errorf("parse nginx conf fail :%s", err)
		return nil, err
	}
	if payload == nil || payload.Config == nil {
		logger.Warnf("parse nginx conf result is nil")
		return nil, errors.New("parse nginx conf result is nil")
	}
	return payload, nil
}

func setPartBlock(srvConf *model.ServerConf, payload *crossplane.Payload) {
	defer func() {
		err := recover()
		if err != nil {
			logger.Warn("setPartBlock fail !")
		}
	}()
	for _, directive := range payload.Config[0].Parsed {
		for _, d := range directive.Block {
			if d.Directive == "upstream" && d.Args[0] == srvConf.ServerName {
				server := 0
				for _, d2 := range d.Block {
					d2.Args[0] = srvConf.Line[server].Ip
					d2.Args[1] = fmt.Sprintf("weight=%s", srvConf.Line[server].Weight)
					server++
				}
			}
		}
	}
}

func writeNginxConf(path string, payload *crossplane.Payload) error {
	var file *os.File
	defer func() {
		if file != nil {
			err := file.Close()
			if err != nil {
				logger.Warn("Close nginx file fail")
			}
		}
	}()
	config := crossplane.Config{
		Parsed: payload.Config[0].Parsed,
	}
	file, err := os.Create(path)
	if err != nil {
		logger.Errorf("open nginx file fail")
		return err
	}
	opts := &crossplane.BuildOptions{
		Indent: 4,    // 4空格缩进
		Header: true, // 包含配置头注释
	}
	// 4. 写入配置文件
	if err = crossplane.Build(file, config, opts); err != nil {
		logger.Errorf("write nginx file fail")
		return err
	}
	return nil
}
